`timescale 1ns/1ps
module top_tb;

  // 时钟和复位信号
  reg ACLK;
  reg ARESETN;
  reg PCLK;
  reg PRESETn;

  // AXI信号
  reg [31:0] AWADDR;
  reg [7:0]  AWLEN;
  reg [2:0]  AWSIZE;
  reg [1:0]  AWBURST;
  reg        AWVALID;
  wire       AWREADY;
  reg [31:0] WDATA;
  reg [3:0]  WSTRB;
  reg        WLAST;
  reg        WVALID;
  wire       WREADY;
  wire [1:0] BRESP;
  wire       BVALID;
  reg        BREADY;

  // APB信号
  reg [31:0] PADDR;
  reg        PWRITE;
  reg [31:0] PWDATA;
  reg        PENABLE;
  reg        PSEL;
  wire [31:0] PRDATA;
  wire        PREADY;
  wire        PSLVERR;

  // 其他输出信号
  wire [31:0] ram_dout;
  wire        burst_done;
  wire [1:0]  matrix_type;
  wire [1:0]  data_type;
  wire        mix_precision;
  wire        axi_start;
  wire [9:0]  axi_write_addr;
  wire [31:0] axi_write_data;
  wire        axi_write_valid;
  wire        axi_done;

  // 实例化顶层模块
  top u_top (
    .*
  );

  // 生成时钟
  initial begin
    ACLK = 0;
    forever #5 ACLK = ~ACLK;
  end

  initial begin
    PCLK = 0;
    forever #10 PCLK = ~PCLK;
  end

  // 复位逻辑
  initial begin
    ARESETN = 0;
    PRESETn = 0;
    #100;
    ARESETN = 1;
    PRESETn = 1;
  end

  // 主测试逻辑
  initial begin
    reg [31:0] a_data[0:63];
    reg [31:0] b_data[0:63];
    reg [31:0] c_exp[0:255];
    integer i;

    // 初始化信号
    AWADDR   = 0;
    AWLEN    = 0;
    AWSIZE   = 0;
    AWBURST  = 0;
    AWVALID  = 0;
    WDATA    = 0;
    WSTRB    = 0;
    WLAST    = 0;
    WVALID   = 0;
    BREADY   = 0;
    PADDR    = 0;
    PWRITE   = 0;
    PWDATA   = 0;
    PENABLE  = 0;
    PSEL     = 0;

    // 等待复位完成
    #200;

    // 通过APB配置参数
    apb_write(32'h00, 2'b00); // matrix_type = GEMM
    apb_write(32'h04, 2'b00); // data_type = int8
    apb_write(32'h08, 1'b0);  // mix_precision = off

    // 加载输入数据
    $readmemh("D:/TPU/SA/TPU/top/systolic_array/testbench/int8_int32/m16n16k16/a_int8_m16n16k16_hex.txt", a_data);
    $readmemh("D:/TPU/SA/TPU/top/systolic_array/testbench/int8_int32/m16n16k16/b_int8_m16n16k16_hex.txt", b_data);

    // 写入矩阵A数据
    axi_write_burst(32'h0000_0000, 64, a_data);

    // 写入矩阵B数据
    axi_write_burst(32'h0000_0040, 64, b_data);

    // 启动计算
    apb_write(32'h0C, 32'h1);

    // 等待计算完成
    wait(axi_done);
    #100;

    // 验证输出数据
    $readmemh("D:/TPU/SA/TPU/top/systolic_array/testbench/int8_int32/m16n16k16/c_int32_m16n16k16.txt", c_exp);
    for(i=0; i<256; i++) begin
      if(u_top.u_ram_ctrl.ram0.ram[i] !== c_exp[i]) begin
        $display("ERROR: Mismatch at address %0h", i);
        $display("Expected: %0h, Got: %0h", c_exp[i], u_top.u_ram_ctrl.ram0.ram[i]);
        $finish;
      end
    end

    $display("TEST PASSED");
    $finish;
  end

  // APB写任务
  task apb_write(input [31:0] addr, input [31:0] data);
    @(posedge PCLK);
    PSEL    <= 1;
    PWRITE  <= 1;
    PADDR   <= addr;
    PWDATA  <= data;
    PENABLE <= 0;
    @(posedge PCLK);
    PENABLE <= 1;
    while(!PREADY) @(posedge PCLK);
    @(posedge PCLK);
    PSEL    <= 0;
    PENABLE <= 0;
  endtask

  // AXI突发写任务
  task axi_write_burst(input [31:0] base_addr, input int len, input reg [31:0] data[]);
    // 地址通道
    @(posedge ACLK);
    AWADDR  <= base_addr;
    AWLEN   <= len-1;
    AWSIZE  <= 3'b10;
    AWBURST <= 2'b01;
    AWVALID <= 1;
    while(!AWREADY) @(posedge ACLK);
    @(posedge ACLK);
    AWVALID <= 0;

    // 数据通道
    for(int i=0; i<len; i++) begin
      @(posedge ACLK);
      WDATA  <= data[i];
      WSTRB  <= 4'b1111;
      WLAST  <= (i == len-1);
      WVALID <= 1;
      while(!WREADY) @(posedge ACLK);
    end
    WVALID <= 0;

    // 响应通道
    BREADY <= 1;
    while(!BVALID) @(posedge ACLK);
    @(posedge ACLK);
    BREADY <= 0;
  endtask

endmodule